<?php

use Phalcon\Mvc\Controller;
use Phalcon\Db\Adapter\Pdo\Mysql as DbAdapter;
use Phalcon\Translate\Adapter\NativeArray as NativeArray;
define("SESSION_LOGIN_USER", "loginMonitorUser");

class ControllerBase extends Controller
{
    //常量

    const SESSION_LOGIN_USER = "loginMonitorUser";
    const SESSION_DOWNLOAD_CENTER = "isLoginDownloadCenter";

    const REQUEST_ACTION_KEY = "action_key";
    const REQUEST_ACTION_ADD = "ACTION_ADD";
    const REQUEST_ACTION_DELETE = "ACTION_DELETE";
    const REQUEST_ACTION_UPDATE = "ACTION_UPDATE";
    const REQUEST_ACTION_LIST = "ACTION_LIST";
    const REQUEST_ACTION_DETAIL = "ACTION_DETAIL";
    const REQUEST_ACTION_UNKONW = "ACTION_UNKNOW";

    public $apiDomain;

    public function beforeExecuteRoute($dispatcher)
    {

    }

    public function afterExecuteRoute($dispatcher)
    {
        // 在找到的action后执行
        $action = $dispatcher->getActionName();
        $name = $dispatcher->getControllerName();
        if(strtolower($name)!="third"){
            $url = "/$name/$action";
            $this->authMenuAccess($url);
        }
    }

    //菜单是否信任
    private function authMenuAccess($url)
    {
        switch ($url) {
            //排除在外的页面访问
            //监控
            case "/firmware/loginFirmwareCenter":
            case "/firmware/firmwareDetail":
            case "/firmware/firmwareDownloadList":
            case "/firmware/firmwareCenter":
            case "/firmware/firmwareCenterDetail":
            case "/firmware/likeFirmware":
            case "/monitor/requestTaskList":
            case "/monitor/requestMyPlaneStat":
            case "/monitor/requestBlockStat":
            case "/monitor/ajaxGetAddressByLngLat":
            case "/monitor/requestTaskDetail":
            case "/monitor/detail4mobile":
            case "/monitor/detail4fix":
            case "/monitor/detail4fixPhone":
            case "/monitor/detail4mobilePhone":
            case "/monitor/monitor4new":
            case "/index/error":
            case "/zone/getNoFlyZone":
            case "/bug/submitSuggestion":
            case "/version/getVideoGSUpdate":
            case "/version/publishVideoGSVersion":
            case "/user/login": {
            };
                break;
            default: {
                $user = $this->getMonitorLoginUser();
                if ($user) {
                    //访问是否为收管制的菜单
                    if ($this->isContainAuthMenu($url, $this->defaultAuthMenu['admin'])) {
                        switch ($user->userRoleId) {
                            case MonitorLoginUser::USER_ROLE_SYSTEM_ADMIN: {
                                $userAuthMenu = $this->getMonitorLoginUser()->userAuthMenu;
                                if ($userAuthMenu) {
                                    $result = strpos($userAuthMenu, $url);
                                    if (is_numeric($result) && result >= 0) {
                                        //合法
                                    } else {
                                        //不合法
                                        $this->goToErrorPage("权限错误", "您越权访问");
                                    }
                                }
                            };
                                break;
                            case MonitorLoginUser::USER_ROLE_SUBSYSTEM_ADMIN: {
                                if (!$this->isContainAuthMenu($url, $this->defaultAuthMenu['subadmin'])) {
                                    $this->goToErrorPage("权限错误", "您越权访问");
                                }
                            };
                                break;
                            case MonitorLoginUser::USER_ROLE_NORMAL: {
                                if (!$this->isContainAuthMenu($url, $this->defaultAuthMenu['normal'])) {
                                    $this->goToErrorPage("权限错误", "您越权访问");
                                }
                            };
                                break;
                        }


                    }
                } else {
                    $this->dispatcher->forward(
                        [
                            "controller" => "user",
                            "action" => "login",
                        ]
                    );

                }
            }
        }
    }

    private function goToErrorPage($title, $message)
    {
        $this->dispatcher->forward(
            [
                "controller" => "index",
                "action" => "error",
            ]
        );
        $this->view->setVars(array("errorTitle" => $title,
            "errorInfo" => $message));
    }

    private function isContainAuthMenu($url, $menuDict)
    {
        foreach ($menuDict as $itemArray) {
            if ($itemArray["menuUrl"] == $url) {
                return true;
            }
            foreach ($itemArray["children"] as $item) {
                if ($item["menuUrl"] == $url) {
                    return true;
                }
            }
        }
        return false;
    }

    /** 用户相关方法 */

    /**
     * 获取请求的动作类型
     * @return mixed
     */
    public function getRequestAction()
    {
        $action = $this->getPost($this::REQUEST_ACTION_KEY);
        if (empty($action)) {
            return $this::REQUEST_ACTION_UNKONW;
        }
        return $action;
    }

    /**
     * 获取当前登录用户
     * @param bool $autoTranferLogin 是否自动跳转到登录界面
     * @return mixed
     */
    public function getMonitorLoginUser($autoTranferLogin = false)
    {
        $expire = $this->redisExpire['user'];
        $user = $this->session->get($this::SESSION_LOGIN_USER);
        $this->redis->setex($user->token, $expire, $user->userId);
        if (empty($user)) {
            if ($autoTranferLogin) {
                $this->response->redirect('../user/login');
                return;
            }
            return null;
        }
        return $user;
    }

    public function isLoginFirmwareCenter()
    {
        $value = $this->session->get($this::SESSION_DOWNLOAD_CENTER);
        if (empty($value)) {
           return false;
        }else {
            return true;
        }
    }

    /**
     * 是否为监控管理员用户
     */
    public function isMonitorAdminUser()
    {
        $user = $this->getMonitorLoginUser(true);
        if (!empty($user)) {
            return $user->isSystemAdmin;
        }
        return false;
    }

    /**
     * 是否为子系统管理员
     * @return bool
     */
    public function isMonitorSubsystemAdminUser()
    {
        $user = $this->getMonitorLoginUser();
        if (!empty($user)) {
            if ($user->userRoleId == MonitorLoginUser::USER_ROLE_SUBSYSTEM_ADMIN) {
                return true;
            }
        }
        return false;
    }

    public function getPost($key, $default = null, $type = null)
    {
        $value = $this->request->getPost($key, $type, $default);
        if (!isset($value)) {
            return $default;
        }
        //$value = str_replace("\\", "\\\\", $value);
        $value = str_replace("'", "\\'", $value);
        return $value;
    }

    public function getQuery($key, $default = null)
    {
        $value = $this->request->getQuery($key, null, $default);
        return $value;
    }


    // 检查用户输入是否合法
    public function checkRequest($validation, $requestField)
    {
        $messages = $validation->validate($requestField);
        if (count($messages)) {
            foreach ($messages as $message) {
                $this->returnError($message->getMessage());
            }
        }
    }

    public function returnResponse($status, $message, $data = "")
    {
        header("Content-Type:application/json; charset=UTF-8");
        $response = json_encode(array('status' => $status, 'message' => $message, 'data' => $data));
        header("content-length:" . strlen($response));
        echo $response;
        exit();
    }

    public function getSqlNumField($field, $default = "null")
    {
        if ($field === "") {
            $field = 0;
        }
        return isset($field) ? "$field" : "$default";
    }

    public function getSqlTextField($field, $default = "null")
    {
        return empty($field) ? ($default == "null" ? "null" : "'$default'") : "'$field'";
    }

    public function getSqlDate($field, $default = "null")
    {

        return empty($field) ? ($default == "null" ? "null" : "'$default'") : "'" . date("Y-m-d H:i:s", strtotime($field)) . "'";
    }

    public function getSqlBoolean($field, $default = "null")
    {
        return empty($field) ? $default : $field;
    }

    public function returnJson($data)
    {
        $this->returnResponse(0, '', $data);
    }

    public function returnSuccess($message = "")
    {
        if (empty($message)) {
            $message = $this->lstr("OPERATION_SUCCESS");
        }
        $this->returnResponse(0, $message);
    }

    public function returnDebug($message = "")
    {
        $this->returnResponse(1, $message);
    }

    public function returnInfo($message = "")
    {
        $this->returnResponse(2, $message);
    }

    public function returnWarning($message = "")
    {
        $this->returnResponse(3, $message);
    }

    public function returnError($message = "")
    {
        $this->returnResponse(4, $message);
    }

    // 返回操作权限错误
    public function returnAuthError($message = "")
    {
        if (empty($message)) {
            $message = $this->lstr("OPERATION_AUTH_ERROR");
        }
        $this->returnResponse(5, $message);
    }

    // 由于权限问题访问接口失败是调用
    public function return401($message = "")
    {
        $this->returnResponse(401, $message);
    }

    // 由于权限问题访问接口失败是调用
    public function return403($message = "")
    {
        $this->returnResponse(403, $message);
    }


    public function curlRequest($url, $method, $data = null, $header = false)
    {

        $method = strtoupper($method);
        //初始化
        $ch = curl_init();
        //设置选项，包括URL
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_NOBODY, FALSE); //表示需要response body
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, FALSE);
        curl_setopt($ch, CURLOPT_AUTOREFERER, TRUE);
        curl_setopt($ch, CURLOPT_TIMEOUT, 15);

        if ((!is_array($data)) && json_decode($data)) {
            if ($header) {
                curl_setopt($ch, CURLOPT_HTTPHEADER, array_merge(array('Content-type: application/json'), $header));
            } else {
                curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type: application/json'));
            }
        } else {
            if ($header) {
                curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
            }
        }

        if ($method == "GET") {
            if (count($data) > 0) {
                $url .= "?" . http_build_query($data);
            }

        } else if ($method == "POST") {
            // post数据
            curl_setopt($ch, CURLOPT_POST, 1);
            if ((!is_array($data))) {
                curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
            } else {
                curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
            }

        } else {
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
            curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
        }
        curl_setopt($ch, CURLOPT_URL, $url);
        //执行并获取HTML文档内容
        $response = curl_exec($ch);
        return $response;
    }

    public function getToken()
    {
        return $_SERVER["HTTP_TOKEN"];
    }

    // 检查用户Nonce，如果合法，那么返回用户信息
    public function getLoginUser($checkUser = false)
    {
        $token = $this->session->get('token');
        $expire = $this->redisExpire['user'];
        if (empty($token)) {
            if ($checkUser == true) {
                return false;
            } else {
                return $this->return401("您没有登录。");
            }
        }

        $sql = "select * from user where cloud_token = '$token'";
        $record = $this->fetchOne($sql, $expire);
        if ($record) {
            unset($record["ios_token"]);
            unset($record["token"]);
            unset($record["password"]);
            if ($record["online"] == 0) {
                if ($checkUser == true) {
                    return false;
                } else {
                    return $this->return403("您的账户被锁定了。");
                }
            }

            $permission = "";
            if (empty($record["permission_p40"])) {
                $permission .= "permission_p40:0;";
            } else {
                $permission .= "permission_p40:1;";
            }
            if (empty($record["permission_local_gps"])) {
                $permission .= "permission_local_gps:0;";
            } else {
                $permission .= "permission_local_gps:1;";
            }
            if (empty($record["video_route"])) {
                $permission .= "video_route:0;";
            } else {
                $permission .= "video_route:1;";
            }
            if(empty($record["full_function"])){
                $permission.= "full_function:0;";
            }
            else{
                $permission.= "full_function:1;";
            }
            $record["permission"] = $permission;
            return $record;
        }

        if ($checkUser == true) {
            return false;
        }
        $this->return403("您没有登录。");
    }

    // 清除缓存中的用户登录信息
    public function clearToken()
    {
        if (isset($_SERVER["HTTP_TOKEN"])) {
            $token = $_SERVER["HTTP_TOKEN"];
            if ($this->isIos()) {
                $sql = "update user set ios_token = null where ios_token = '$token'";
            } else {
                $sql = "update user set token = null where token = '$token'";
            }
            $this->execute($sql);
        }
    }

    // 检查用户Nonce，如果合法，那么返回用户信息
    public function getLoginAdminUser($checkUser = false)
    {
        $token = $_SERVER["HTTP_TOKEN"];

        if (empty($token)) {
            if ($checkUser == true) {
                return false;
            } else {
                return $this->return401("您没有登录。");
            }
        }

        $sql = "select * from fos_user_user where token = '$token'";
        $record = $this->fetchOne($sql);

        if ($record) {
            unset($record["password"]);
            if ($record["enabled"] == 0) {
                if ($checkUser == true) {
                    return false;
                } else {
                    return $this->return403("您的账户被锁定了。");
                }
            }
            return $record;
        }

        if ($checkUser == true) {
            return false;
        }
        $this->return403("您没有登录。");
    }

    // 清除缓存中的用户登录信息
    public function clearAdminToken()
    {
        if (isset($_SERVER["HTTP_TOKEN"])) {
            $token = $_SERVER["HTTP_TOKEN"];
            $sql = "update fos_user_user set token = null where token = '$token'";
            $this->execute($sql);
        }
    }

    // 获得用户的请求头信息
    function get_all_headers()
    {
        $headers = array();

        foreach ($_SERVER as $key => $value) {
            if (substr($key, 0, 5) === 'HTTP_') {
                $key = substr($key, 5);
                $key = strtolower($key);
                $key = str_replace('_', ' ', $key);
                $key = ucwords($key);
                $key = str_replace(' ', '-', $key);

                $headers[$key] = $value;
            }
        }
        return $headers;
    }

    function sendValidateSmsByInvoice($phone, $validate)
    {
//         $template = "【飞马机器人】 您的验证码为$validate,请于10分钟内正确输入验证码";
//         $data = array(
//                 "apikey" => 'a19303378293a0145293af7c1be17e12',
//                 "mobile" => '+86'.$phone,
//                 "text" => $validate,
//         );

//         $result = $this->curlRequest("https://sms.yunpian.com/v2/sms/single_send.json", "post", $data);
//         file_put_contents("./log_" . date("Y-m-d") . ".txt",  "\n".date("H:i:s", time()).':'.__METHOD__.':'."yunpian return:$json_data \r\n", FILE_APPEND);
//         //$r = json_decode($result, 1);
//         return json_decode($result,true);

        $ch = curl_init();
        // 必要参数
        $apikey = $this->yunpian['apikey']; //修改为您的apikey(https://www.yunpian.com)登录官网后获取
        $mobile = "$phone"; //请用手机号代替
        $text = "【飞马机器人】您的验证码为" . $validate . "，请于10分钟内正确输入验证码";
//         urlencode(urlencode("#code#") + "=" + urlencode("1234") + "&" + urlencode("#company#") + "=" + urlencode("云片网"))
        // 发送短信
        $data = array('text' => $text, 'apikey' => $apikey, 'mobile' => $mobile);
        curl_setopt($ch, CURLOPT_URL, $this->yunpian['yp_sms_host']);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $json_data = curl_exec($ch);
        //解析返回结果（json格式字符串）
        return json_decode($json_data, true);

    }

    function sendSmsContent($phone, $text)
    {
        $appid = $this->Qcloud['AppID'];
        $appkey = $this->Qcloud['AppKey'];
        
        try {
            //                         $sender = new Qcloud\Sms\SmsSingleSender($appid, $appkey);
            //                         require_once dirname(__FILE__).'./../plugins/Qcloudsms/src/SmsSingleSender.php';
            $sender = new Qcloud\Sms\SmsSingleSender($appid, $appkey);
            $ext = md5 (uniqid(mt_rand(), true));
            $result = $sender->send(0, "86", $phone, $text, "", $ext);
            $rsp = json_decode($result,true);
            file_put_contents("./Qcloud_" . date("Y-m-d") . ".txt", "\n" . date("H:i:s", time()) . ':' . __METHOD__ . ':' . "Qcloud return:" . $result . " \r\n", FILE_APPEND);
            if($rsp['result']!=0){
                file_put_contents("./Qcloud_" . date("Y-m-d") . ".txt", "\n" . date("H:i:s", time()) . ':' . __METHOD__ . ':' . "Qcloud return:" . $rsp['errmsg'] . " \r\n", FILE_APPEND);
            }
            $rsp['code']=$rsp['result'];
            return $rsp;
            //                     echo $result;
        } catch(\Exception $e) {
            echo var_dump($e);
        }

    }
    
    function sendYunpianContent($phone, $text)
    {
        $ch = curl_init();
        // 必要参数
        $receivekey = $this->yunpian['apikey']; //修改为您的apikey(https://www.yunpian.com)登录官网后获取
        $mobile = "$phone"; //请用手机号代替
        //         urlencode(urlencode("#code#") + "=" + urlencode("1234") + "&" + urlencode("#company#") + "=" + urlencode("云片网"))
        // 发送短信
        $data = array('text' => $text, 'apikey' => $receivekey, 'mobile' => $mobile);
        curl_setopt($ch, CURLOPT_URL, $this->yunpian['yp_sms_host']);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $json_data = curl_exec($ch);
        //解析返回结果（json格式字符串）
        return json_decode($json_data, true);
        
    }

    function sendAddUserValidateSms($phone, $adminName, $systemName)
    {
        $ch = curl_init();
        // 必要参数
        $apikey = $this->yunpian['apikey']; //修改为您的apikey(https://www.yunpian.com)登录官网后获取
        $mobile = "$phone"; //请用手机号代替
        $text = "【飞马机器人】" . $adminName . "希望把你加入到" . $systemName . "中去，回复TYTJ,添加到该系统中去";
        //         urlencode(urlencode("#code#") + "=" + urlencode("1234") + "&" + urlencode("#company#") + "=" + urlencode("云片网"))
        // 发送短信
        $data = array('text' => $text, 'apikey' => $apikey, 'mobile' => $mobile);
        curl_setopt($ch, CURLOPT_URL, $this->yunpian['yp_sms_host']);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $json_data = curl_exec($ch);

        //解析返回结果（json格式字符串）
        return json_decode($json_data, true);

    }

    function sendValidateSms($phone, $validate)
    {

        $timestamp = date("YmdHis000");
        $sid = 'cea7ae506f76cc82b24c539483f9993d';
        $appId = 'c88277e24d3c4b40be9cc994aab6a76f';
        $sign = md5($sid . $timestamp . 'd9d5f86bac23caf4249bb532ffdff3cb');

        $data = array(
            'sid' => $sid,
            'appId' => $appId,
            'time' => $timestamp,
            'sign' => $sign,
            'to' => $phone,
            'templateId' => 15846,
            'param' => $validate . ',10',
        );

        $result = $this->curlRequest("http://www.ucpaas.com/maap/sms/code", "post", $data);
        return $result;
    }

    public function getHuanxinToken()
    {
        if ($this->redis->exists("huanxin-token")) {
            // 如果redis中存在token
            $token = $this->redis->get("huanxin-token");
        } else {
            $json = '{"grant_type":"client_credentials","client_id":"YXA6lNamEPAHEeSFMH-yLgpC-w","client_secret":"YXA6jK1pLA8jbuwyhfm4gzXIObij8Ms"}';
            $response = $this->curlRequest("https://a1.easemob.com/thewbb/aixiangsu/token", "post", $json);
            $token = json_decode($response, true)["access_token"];
            $this->redis->setex("huanxin-token", 3600 * 24 * 3, $token);  // token保存三天，环信官方说明是token可以使用7天
        }

        return $token;
    }

    public function huanxunRegisterUser($username)
    {
        $json = '{"username":"' . $username . '","password":"11204122"}';
        $response = $this->curlRequest("https://a1.easemob.com/thewbb/aixiangsu/users", "post", $json);
        return $response;
    }

    public function huanxinChangePassword($username, $newPassword)
    {
        $response = $this->curlRequest("https://a1.easemob.com/thewbb/aixiangsu/users/$username/password"
            , "PUT"
            , '{"newpassword":"' . $newPassword . '"}'
            , array("Authorization: Bearer " . $this->getHuanxinToken()));
        return $response;
    }

    public function huanxinRemoveUser($username)
    {
        $response = $this->curlRequest("https://a1.easemob.com/thewbb/aixiangsu/users/$username"
            , "DELETE"
            , array()
            , array("Authorization: Bearer " . $this->getHuanxinToken()));
        return $response;
    }

    public function dateFormat($date)
    {
        if (empty($date)) {
            return $date;
        }
        $date = strtotime($date);
        if ($date < 0) {
            return null;
        }
        $timestamp = time() - $date;

        if ($timestamp < 60) {
            return "刚刚";
        } else if (date("Y-m-d H", time()) == date("Y-m-d H", $date)) {
            return "" . ceil($timestamp / 60) . "分钟前";
        } else if (date("Y-m-d", time()) == date("Y-m-d", $date)) {
            return "" . ceil($timestamp / 3600) . "小时前";
        } else if ($timestamp < 60 * 60 * 24 * 2) {
            return "昨天 " . date("H:i", $date);
        } else if ($timestamp < 60 * 60 * 24 * 3) {
            return "前天 " . date("H:i", $date);
        } else if (date("Y-m", time()) == date("Y-m", $date)) {
            return "" . ceil($timestamp / 86400) . "天前";
        } else if (date("Y", time()) == date("Y", $date)) {
            return date("n月j日", $date);
        } else {
            return date("Y年n月j日", $date);
        }
    }


    public function pushAlias($phone, $content, $extras = null)
    {
        $arrPhones = explode(",", $phone);

        if (empty($extras)) {
            $json = '
        {
            "platform":"all",
            "audience":{
            "alias" : ' . json_encode($arrPhones, true) . '
            },
            "notification":{
                "android": {
                    "alert": "' . $content . '",
                    "title": "爱像素"
                },
                "ios": {
                    "alert": "' . $content . '",
                    "sound": "default",
                    "badge": "+1"
                }

            }
        }';
        } else {
            $json = '
        {
            "platform":"all",
            "audience":{
            "alias" : ' . json_encode($arrPhones, true) . '
            },
            "notification":{
                "android": {
                    "alert": "' . $content . '",
                    "title": "爱像素",
                    "extras":' . json_encode($extras, true) . '
                },
                "ios": {
                    "alert": "' . $content . '",
                    "sound": "default",
                    "badge": "+1",
                    "extras":' . json_encode($extras, true) . '
                }

            }
        }';
        }
        $header = array("Authorization: Basic " . base64_encode("6e807bb273ad481e555ba95b:5876d81ad4f7098e6dc11739"));
        $response = $this->curlRequest("https://api.jpush.cn/v3/push", "post", $json, $header);
        return $response;
    }

    public function pushAll($content)
    {
        $json = '{"platform":"all","audience":"all","notification":{"alert":"' . $content . '"}}';
        $header = array("Authorization: Basic " . base64_encode("6e807bb273ad481e555ba95b:5876d81ad4f7098e6dc11739"));
        $response = $this->curlRequest("https://api.jpush.cn/v3/push", "post", $json, $header);
        return $response;
    }

    function isTel($tel, $type = '')
    {
        $regxArr = array(
            'sj' => '/^(\+?86-?)?(18|15|13)[0-9]{9}$/',
            'local' => '/^\d{7,9}(-\d+)?$/',
            'tel' => '/^[0-9]{11}$/',
            '400' => '/^400(-\d{3,4}){2}$/',
        );
        if ($type && isset($regxArr[$type])) {
            return preg_match($regxArr[$type], $tel) ? true : false;
        }
        foreach ($regxArr as $regx) {
            if (preg_match($regx, $tel)) {
                return true;
            }
        }
        return false;
    }

    function isNotJson($json)
    {
        return is_null(json_decode($json));
    }

    function guid()
    {
        return md5(uniqid(mt_rand(), true));
    }

    function download_by_path($path_name, $save_name, $download_name)
    {
        header("Content-type:text/html;charset=utf-8");

        $file_name = $save_name;
        //用以解决中文不能显示出来的问题
        $file_name = iconv("utf-8", "gb2312", $file_name);
        $file_sub_path = $path_name;
        $file_path = $file_sub_path . $file_name;
        //首先要判断给定的文件存在与否
        if (!file_exists($file_path)) {
            echo "没有该文件";
            return;
        }
        $fp = fopen($file_path, "r");
        $file_size = filesize($file_path);
        //下载文件需要用到的头
        Header("Content-type: application/octet-stream");
        Header("Accept-Ranges: bytes");
        Header("Content-Length:" . $file_size);
        Header("Content-Disposition: attachment; filename=" . $download_name);
        $buffer = 1024;
        $file_count = 0;
        //向浏览器返回数据
        while (!feof($fp) && $file_count < $file_size) {
            $file_con = fread($fp, $buffer);
            $file_count += $buffer;
            echo $file_con;
        }
        fclose($fp);
    }

    public function getUploadFile()
    {
        foreach ($_FILES as $file) {
            return $file;
        }
    }

    public function downloadByBlob($blob, $filename)
    {
        Header("Content-type: application/octet-stream");
        Header("Accept-Ranges: bytes");
        Header("Content-Length:" . strlen($blob));
        Header("Content-Disposition: attachment; filename=" . $filename);
        echo $blob;
    }

    function desEncrypt($str)
    {
        return openssl_encrypt($str, 'DES-CBC', 'feimakey', 0, "12345678");
    }


    function desDecrypt($str)
    {
        return openssl_decrypt($str, 'DES-CBC', 'feimakey', 0, "12345678");
    }

    // 矩阵乘法函数
    function matrixMulti($m1, $m2)
    {
        $r = count($m1);
        $c = count($m2[0]);
        $p = count($m2);
        if (count($m1[0]) != $p) {
            throw new Exception('Incompatible matrixes');
        }
        $m3 = array();
        for ($i = 0; $i < $r; $i++) {
            for ($j = 0; $j < $c; $j++) {
                $m3[$i][$j] = 0;
                for ($k = 0; $k < $p; $k++) {
                    $m3[$i][$j] += $m1[$i][$k] * $m2[$k][$j];
                }
            }
        }
        return ($m3);
    }

    // 判断一个经纬度坐标是否在一个经纬度坐标列表形成的闭合多边形中
    function inPolygon($polygon, $p)
    {
        $polygonTemp = $polygon;
        $polygonTemp[] = $polygon[0];

        $deg = 0;
        for ($i = 0; $i < count($polygonTemp) - 1; $i++) {
            $angleA = rad2deg(atan2($polygonTemp[$i]["lat"] - $p["lat"], $polygonTemp[$i]["lng"] - $p["lng"]));

            $angleB = rad2deg(atan2($polygonTemp[$i + 1]["lat"] - $p["lat"], $polygonTemp[$i + 1]["lng"] - $p["lng"]));

            $angleC = $angleA - $angleB;

            // 点在边上
            if (abs(180 - $angleC) < 0.01) {
                return true;
            }

            // 处理角度超过正负180的情况
            if ($angleC >= 180) {
                $angleC = $angleC - 360;
            } else if ($angleC <= -180) {
                $angleC = $angleC + 360;
            }
            $deg += $angleC;
        }
        //echo $deg.", ".(abs($deg) - 360).";   ";
        if (abs(abs($deg) - 360) < 0.01) {
            return true;
        }

        return false;
    }

    function push($data, $toUserId, $token = null)
    {
        $record = $this->fetchOne("select * from user where id  = $toUserId");
        if (empty($record)) {
            file_put_contents("./log_" . date("Y-m-d") . ".txt", __METHOD__ . date(" Y-m-d H:i:s") . ':' . "push error:not found user id :$toUserId" . "\r\n", FILE_APPEND);
            return false;
        }

        if (empty($token)) {
            $fromId = null;
        } else {
            $fromId = $this->getLoginUser(true)["id"];
        }

        $this->insert("tcp_push", array(
            "action" => $data["action"],
            "data" => json_encode($data),
        ));

        if ($data["action"] != "news") {
            $pushId = $this->lastInsertId();

            $this->insert("tcp_push_relation", array(
                "tcp_push_id" => $pushId,
                "from_id" => $fromId,
                "to_id" => $toUserId,
            ));
        }

        $socketData = json_encode(array("action" => "server_push", "to_id" => $toUserId)) . "SWOOLEFN";
        $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
        socket_connect($socket, $this->host['tcp_host'], 19503);
        socket_write($socket, $socketData, strlen($socketData));
        socket_close($socket);
    }


    function web_push($data, $toUserId, $fromId = 0)
    {
        $this->pushRealMessage2Client($data, $toUserId, $fromId, "push_to_web", 1);
    }
    
    function pc_push($data, $toUserId, $fromId)
    {

        $this->pushRealMessage2Client($data, $toUserId, $fromId, "push_to_pc", 0);
    }

    private function pushRealMessage2Client($data, $toUserId, $fromId, $serverAction, $clientType)
    {
        $record = $this->fetchOne("select * from user where id  = $toUserId");
        if (empty($record)) {
            file_put_contents("./log_" . date("Y-m-d") . ".txt", __METHOD__ . date(" Y-m-d H:i:s") . ':' . "push error:not found user id :$toUserId" . "\r\n", FILE_APPEND);
            return false;
        }

        if (!empty($fromId)) {
            $record = $this->fetchOne("select * from user where id  = $fromId");
            if (empty($record)) {
                file_put_contents("./log_" . date("Y-m-d") . ".txt", __METHOD__ . date(" Y-m-d H:i:s") . ':' . "push error:not found user id :$toUserId" . "\r\n", FILE_APPEND);
                return false;
            }
        }

        $pushId = $this->insert("tcp_push", array(
            "action" => $data["action"],
            "status" => 2,
            "data" => json_encode($data),
            "type" => $clientType
        ));
        $msgToken=$data["token"]?$data["token"]:"";
        $this->insert("tcp_push_relation", array(
            "tcp_push_id" => $pushId,
            "from_id" => $fromId,
            "to_id" => $toUserId,
            "token"=>$msgToken
        ));
        $socketData = json_encode(array("action" => $serverAction, "to_id" => $toUserId)) . "SWOOLEFN";
        $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
        socket_connect($socket, $this->host['tcp_host'], 19503);
        socket_write($socket, $socketData, strlen($socketData));
        socket_close($socket);
    }


    function tcp_push($data, $toUserId, $fromId)
    {
        $record = $this->fetchOne("select * from user where id  = $toUserId");
        if (empty($record)) {
            file_put_contents("./log_" . date("Y-m-d") . ".txt", __METHOD__ . date(" Y-m-d H:i:s") . ':' . "push error:not found user id :$toUserId" . "\r\n", FILE_APPEND);
            return false;
        }

        if (!empty($fromId)) {
            $record = $this->fetchOne("select * from user where id  = $fromId");
            if (empty($record)) {
                file_put_contents("./log_" . date("Y-m-d") . ".txt", __METHOD__ . date(" Y-m-d H:i:s") . ':' . "push error:not found user id :$toUserId" . "\r\n", FILE_APPEND);
                return false;
            }
        }

        $pushId = $this->insert("tcp_push", array(
            "action" => $data["action"],
            "status" => 2,
            "data" => json_encode($data),
            "type" => 0
        ));

        $this->insert("tcp_push_relation", array(
            "tcp_push_id" => $pushId,
            "from_id" => $fromId,
            "to_id" => $toUserId,
        ));
        
        $socketData = json_encode(array("action" => "server_push", "to_id" => $toUserId)) . "SWOOLEFN";
        $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
        socket_connect($socket, $this->host['tcp_host'], 19503);
        socket_write($socket, $socketData, strlen($socketData));
        socket_close($socket);
    }

    /**
     * 请求Tcp
     * @param $data
     * @param $token
     * @param int $port
     * @param string $type
     * @return mixed
     */
    protected function requestTcp($data, $token, $port = 8081, $type = 'post')
    {
        if (!empty($this->host['api_host'])) {
            $index = strrpos($this->host['api_host'], ':');
            $host = substr($this->host['api_host'], 0, $index);
            $port = substr($this->host['api_host'], $index + 1);
        } else
            $host = $_SERVER['SERVER_ADDR'];
        return $this->requestBySocket('/tcpclient/api', $data, ['token' => $token], $port, $host, $type);
    }


    protected function requestApi($uri, $data, $header = [], $port = 8081, $type = 'post')
    {
        if (!empty($this->host['api_host'])) {
            $index = strrpos($this->host['api_host'], ':');
            $host = substr($this->host['api_host'], 0, $index);
            $port = substr($this->host['api_host'], $index + 1);
        } else
            $host = $_SERVER['SERVER_ADDR'];
        return $this->requestBySocket($uri, $data, $header, $port, $host, $type);
    }


    /**
     * Socket请求接口
     * @param $data
     * @param array $header
     * @param string $type
     * @return mixed
     */
    protected function requestBySocket($url, $data, $header = '', $port = 8081, $host = false, $type = 'post', $showResponse = false)
    {
        if (empty($url))
            return false;

        $host = empty($host) ? $_SERVER['SERVER_ADDR'] : $host;
        $host = str_replace('http://', '', $host);

        $type = empty($type) ? 'POST' : $type;
        $type = strtoupper($type);
        $data = http_build_query($data);
        $fp = fsockopen($host, $port);
        if (!$fp) {
            return false;
        }
        $out = "$type ${url} HTTP/1.1\r\n";
        $out .= "Host:${host}\r\n";
        $out .= "Content-type:application/x-www-form-urlencoded\r\n";
        $out .= "Content-length:" . strlen($data) . "\r\n";
        foreach ($header as $key => $val) {
            $out .= "$key:$val\r\n";
        }
        $out .= "Connection:close\r\n\r\n";
        $out .= "${data}";
        if ($showResponse) {
            fwrite($fp, $out);
            while (!feof($fp)) {
                echo fgets($fp, 128);
            }
        } else
            fputs($fp, $out);

        fclose($fp);
        return true;
    }

    public function isAndroid()
    {
        if (preg_match('/android/', strtolower($_SERVER["HTTP_USER_AGENT"]))) {
            return 1;
        }
        return 0;
    }

    public function isIos()
    {
        if (preg_match('/iphone/', strtolower($_SERVER["HTTP_USER_AGENT"]))) {
            return 1;
        }

        if (preg_match('/ipad/', strtolower($_SERVER["HTTP_USER_AGENT"]))) {
            return 1;
        }
        return 0;
    }

    public function isWeixin()
    {

        if (preg_match('/micromessenger/', strtolower($_SERVER["HTTP_USER_AGENT"]))) {
            return 1;
        }
        return 0;
    }

    /******************************    数据库实用基本方法  ***********************************************************/


    public function fetchAll($sql, $cacheTime = null)
    {
        if (empty($cacheTime)) {
            return $this->dbQuery->fetchAll($sql, Phalcon\Db::FETCH_ASSOC);
        } else {
            if ($this->redis->exists("sql:$sql")) {
                // 如果redis中存在缓存内容
                return json_decode($this->redis->get("sql:$sql"), true);
            } else {
                // 如果redis中不存在
                $value = json_encode($this->dbQuery->fetchAll($sql, Phalcon\Db::FETCH_ASSOC), true);
                $this->redis->setex("sql:$sql", $cacheTime, $value);
                return $value;
            }
        }
    }

    public function fetchOne($sql, $cacheTime = null)
    {
        if (empty($cacheTime)) {
            return $this->dbQuery->fetchOne($sql, Phalcon\Db::FETCH_ASSOC);
        } else {
            if ($this->redis->exists("sql:$sql")) {
                // 如果redis中存在缓存内容
                return json_decode($this->redis->get("sql:$sql"), true);
            } else {
                // 如果redis中不存在
                $value = json_encode($this->dbQuery->fetchOne($sql, Phalcon\Db::FETCH_ASSOC), true);
                $this->redis->setex("sql:$sql", $cacheTime, $value);
                return json_decode($value, true);
            }
        }
    }

    /**
     * @param $sql
     * @param null $cacheTime 单位秒
     * @return mixed
     */
    public function fetchColumn($sql, $cacheTime = null)
    {
        if (empty($cacheTime)) {
            return $this->dbQuery->fetchColumn($sql);
        } else {
            if ($this->redis->exists("sql:$sql")) {
                // 如果redis中存在缓存内容
                return $this->redis->get("sql:$sql");
            } else {
                // 如果redis中不存在
                $value = $this->dbQuery->fetchColumn($sql);
                $this->redis->setex("sql:$sql", $cacheTime, $value);
                return $value;
            }
        }
    }

    public function execute($sql)
    {
        return $this->dbExecute->execute($sql);
    }

    /*
    * 删除一条数据方法
    * @param1 $table, $where=array('id'=>'1') 表名 条件
    * @return 受影响的行数
    */
    public function deleteOne($table, $where)
    {
        if(is_array($where)){
            foreach ($where as $key => $val) {
                $condition = $key.'='.$val;
            }
        } else {
            $condition = $where;
        }
        $sql = "delete from $table where $condition";
        return $this->execute($sql);
    }

    /*
    * 删除多条数据方法
    * @param1 $table, $isList 表名 id列表
    * @return 受影响的行数
    */
    public function deleteAllById($table, $idList)
    {
        $idStr = "";
        foreach ($idList as $item) {
            $idStr .= $item;
            $idStr .= ",";
        }
        $idStr = rtrim($idStr, ",");
        $sql = "delete from $table where id in ($idStr)";
        return $this->execute($sql);
    }

    function update($table, $data, $where, $isSaveLog = true)
    {
        $database_name = $this->database->dbname;
        $records = $this->fetchAll("select COLUMN_NAME from information_schema.COLUMNS where table_name = '$table' and table_schema = '$database_name'");
        if (empty($records)) {
            throw new Exception("table not exist");
        }

        // 筛选出数据表中存在的字段
        $fields = array();
        foreach ($data as $key => $value) {
            $index = array_search($key, array_column($records, 'COLUMN_NAME'));
            if (is_numeric($index)) {
                $fields[$key] = $value;
            }
        }

        // 拼接sql字符串
        $strFields = "";
        foreach ($fields as $key => $value) {
            $strFields .= "$key = :$key,";
        }
        if (empty($strFields)) {
            throw new Exception("error fields");
        }

        if (empty($where)) {
            throw new Exception("where must not be null");
        }

        $strFields = substr($strFields, 0, -1);

        $sth = $this->dbExecute->prepare("update $table set $strFields where $where");

        $params = array();
        foreach ($fields as $key => $value) {
            $params[":" . $key] = $value;
        }
        // 执行sql

        $sth->execute($params);
        if ($isSaveLog) {
            $this->saveUpdateLog($table, $data, $where);
        }

        return $sth->rowCount();
    }

    function insert($table, $data, $isSaveLog = false)
    {
        $database_name = $this->database->dbname;
        $records = $this->fetchAll("select COLUMN_NAME from information_schema.COLUMNS where table_name = '$table' and table_schema = '$database_name'");
        if (empty($records)) {
            throw new Exception("table not exist");
        }

        // 筛选出数据表中存在的字段
        $fields = array();
        foreach ($data as $key => $value) {
            $index = array_search($key, array_column($records, 'COLUMN_NAME'));
            if (is_numeric($index)) {
                $fields[$key] = $value;
            }
        }

        // 拼接sql字符串
        $strFields = "";
        $strValues = "";
        foreach ($fields as $key => $value) {
            $strFields .= "$key,";
            $strValues .= ":$key,";
        }
        if (empty($strFields)) {
            throw new Exception("error fields");
        }

        $strFields = substr($strFields, 0, -1);
        $strValues = substr($strValues, 0, -1);
        $sth = $this->dbExecute->prepare("insert into $table($strFields) values($strValues)");

        $params = array();
        foreach ($fields as $key => $value) {
            $params[":" . $key] = $value;
        }
        // 执行sql
        $sth->execute($params);
        //存储插入数据
        if ($isSaveLog) {
            $this->saveInsertLog($table, $data);
        }
        return $this->dbExecute->lastInsertId();
    }

    public function begin()
    {
        $this->dbExecute->begin();
    }

    public function commit()
    {
        $this->dbExecute->commit();
    }

    public function rollback()
    {
        $this->dbExecute->rollback();
    }

    public function lastInsertId()
    {
        return $this->dbExecute->lastInsertId();
    }

    public function affectedRows()
    {
        return $this->dbExecute->affectedRows();
    }


    /**
     * @param $name
     * @param $value
     * @return mixed
     */
    public function filedItemChanged($table, $name, $value)
    {
        return $value;
    }

    /******************************    腾讯云COS    ***********************************************************/
    /**
     * 获取签名
     * @param string $method 请求类型 method
     * @param string $pathname 文件名称
     * @return string 签名字符串
     */
    protected function getAuthorization($method, $pathname)
    {
        $SecretId = $this->filesCos['secret_id'];
        $SecretKey = $this->filesCos['secret_key'];

        // 整理参数
        $queryParams = array();
        $headers = array();
        $method = strtolower($method ? $method : 'get');
        $pathname = $pathname ? $pathname : '/';
        substr($pathname, 0, 1) != '/' && ($pathname = '/' . $pathname);
        // 工具方法
        function getObjectKeys($obj)
        {
            $list = array_keys($obj);
            sort($list);
            return $list;
        }
        function obj2str($obj)
        {
            $list = array();
            $keyList = getObjectKeys($obj);
            $len = count($keyList);
            for ($i = 0; $i < $len; $i++) {
                $key = $keyList[$i];
                $val = isset($obj[$key]) ? $obj[$key] : '';
                $key = strtolower($key);
                $list[] = rawurlencode($key) . '=' . rawurlencode($val);
            }
            return implode('&', $list);
        }
        // 签名有效起止时间
        $now = time() - 1;
        $expired = $now + 600; // 签名过期时刻，600 秒后
        // 要用到的 Authorization 参数列表
        $qSignAlgorithm = 'sha1';
        $qAk = $SecretId;
        $qSignTime = $now . ';' . $expired;
        $qKeyTime = $now . ';' . $expired;
        $qHeaderList = strtolower(implode(';', getObjectKeys($headers)));
        $qUrlParamList = strtolower(implode(';', getObjectKeys($queryParams)));
        // 签名算法说明文档：https://www.qcloud.com/document/product/436/7778
        // 步骤一：计算 SignKey
        $signKey = hash_hmac("sha1", $qKeyTime, $SecretKey);
        // 步骤二：构成 FormatString
        $formatString = implode("\n", array(strtolower($method), $pathname, obj2str($queryParams), obj2str($headers), ''));
        // 步骤三：计算 StringToSign
        $stringToSign = implode("\n", array('sha1', $qSignTime, sha1($formatString), ''));
        // 步骤四：计算 Signature
        $qSignature = hash_hmac('sha1', $stringToSign, $signKey);
        // 步骤五：构造 Authorization
        $authorization = implode('&', array(
            'q-sign-algorithm=' . $qSignAlgorithm,
            'q-ak=' . $qAk,
            'q-sign-time=' . $qSignTime,
            'q-key-time=' . $qKeyTime,
            'q-header-list=' . $qHeaderList,
            'q-url-param-list=' . $qUrlParamList,
            'q-signature=' . $qSignature
        ));
        return $authorization;
    }

    /******************************    日志相关    ***********************************************************/


    protected function saveInsertLog($table = "", $field = "")
    {
        return $this->saveOperationLog("insert_" . $table, $table, $field, "");
    }


    protected function saveSelectLog($table = "", $field = "", $where = "")
    {
        return $this->saveOperationLog("select_" . $table, $table, $field, $where);
    }


    protected function saveDeleteLog($table = "", $field = "", $where = "")
    {
        return $this->saveOperationLog("delete_" . $table, $table, $field, $where);
    }

    protected function saveUpdateLog($table = "", $field = "", $where = "")
    {
        return $this->saveOperationLog("update_" . $table, $table, $field, $where);
    }

    /**
     * @param $action 动作
     * @param string $table 表
     * @param string $field 字段
     * @param string $where 条件
     * @param string $value 值
     * @return bool
     */
    protected function saveOperationLog($action, $table = "", $field = "", $where = "")
    {

        return $this->saveSystemOperationLog($action, json_encode(array(
            "table" => $table,
            "field" => $field,
            "where" => $where,
        )));
    }

    protected function saveSystemOperationLog($action, $content = "")
    {
        $user = $this->getMonitorLoginUser();
        if (!empty($user)) {

            $sth = $this->dbExecute->prepare("insert into system_operation_log
(id,operation_type,operation_content,operation_user_id,operation_user_info)values
(:id,:operation_type,:operation_content,:operation_user_id,:operation_user_info)");
            // 执行sql
            $sth->execute(array(
                ":id" => $this->guid(),
                ":operation_type" => $action,
                ":operation_content" => $content,
                ":operation_user_id" => $user->userId,
                ":operation_user_info" => ("" . $user->phone)
            ));
            return true;
        }
        return false;
    }

    /**
     * @param [base64]
     * @param $path
     */
    public function base64_image_content($base64_image_content, $path)
    {
        if (preg_match('/^(data:\s*image\/(\w+);base64,)/', $base64_image_content, $result)){
            $type = $result[2];
            $new_file = $path."/".date('Ymd',time())."/";
            if(!file_exists($new_file)){
                //检查是否有该文件夹，如果没有就创建，并给予最高权限
                mkdir($new_file, 0777);
            }
            $new_file = $new_file.time().".{$type}";
            if (file_put_contents($new_file, base64_decode(str_replace($result[1], '', $base64_image_content)))){
                return $new_file;
            }else{
                return false;
            }
        }else{
            return false;
        }
    }



    /******************************    国际化   ***********************************************************/

    /**
     *
     * @param $key
     * @param null $placeHolder
     * @return mixed
     */
    protected function lstr($key, $placeHolder = null)
    {
        return $this->getTranslation()->_($key, $placeHolder);
    }

    /**
     * 获取国际化翻译匹配
     *
     * 示例代码:
     * $t=$this->getTranslation();
     * echo $t->_("hi-name",array("name"=>"women"));
     *
     * @return NativeArray
     */
    protected function getTranslation()
    {

        $language = $this->request->getBestLanguage();
        $language = str_replace("_", "-", strtolower($language));
        $messages = [];
        $translationFile = __DIR__ . '/../../app/language/' . $language . '.php';

        if (file_exists($translationFile)) {
            require $translationFile;
        } else {
            // Fallback to some default
            require __DIR__ . '/../../app/language/zh-cn.php';;
        }

        return new NativeArray(
            [
                'content' => $messages,
            ]
        );
    }


}
